package home.contaduria.dao.jpa;

import home.contaduria.dao.GenericDao;
import home.contaduria.domain.AbstractEntity;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

public abstract class GenericDaoJpaImpl<T extends AbstractEntity<PK>, PK extends Serializable>
		implements GenericDao<T, PK> {
	private Class<AbstractEntity<PK>> clazz;

	@PersistenceContext
	private EntityManager entityManager;

	@SuppressWarnings("unchecked")
	public GenericDaoJpaImpl() {
		Type[] types = ((ParameterizedType) getClass().getGenericSuperclass())
				.getActualTypeArguments();

		if (types[0] instanceof ParameterizedType) {
			// If the class has parameterized types, it takes the raw type.
			ParameterizedType type = (ParameterizedType) types[0];
			clazz = (Class<AbstractEntity<PK>>) type.getRawType();
		} else {
			clazz = (Class<AbstractEntity<PK>>) types[0];
		}
	}

	public GenericDaoJpaImpl(Class<AbstractEntity<PK>> clazz) {
		this.clazz = clazz;
	}

	@Override
	public void create(T newInstance) {
		this.entityManager.persist(newInstance);
	}

	@SuppressWarnings("unchecked")
	@Override
	public T read(PK id) {
		return (T) this.entityManager.find(clazz, id);
	}

	@Override
	public void update(T transientObject) {
		this.entityManager.merge(transientObject);
	}

	@Override
	public void delete(T persistentObject) {
		this.entityManager.remove(persistentObject);
	}

	protected EntityManager getEntityManager() {
		if (entityManager == null) {
			throw new IllegalStateException(
					"Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
		}
		return entityManager;
	}
}
